package de.bazinga.rotw.base.attacker;

import java.util.Iterator;
import java.util.Random;
import java.util.Vector;

import com.jme.intersection.PickData;
import com.jme.intersection.PickResults;
import com.jme.intersection.TrianglePickResults;
import com.jme.math.Ray;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Spatial;
import com.jmex.game.state.GameStateManager;
import com.jmex.terrain.TerrainBlock;

import de.bazinga.rotw.base.Flag;
import de.bazinga.rotw.collision.CollidableObjects;
import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.gameModes.DefendYourBase;
import de.bazinga.rotw.network.BasicSyncManager;
import de.bazinga.rotw.network.Server;
import de.bazinga.rotw.network.message.HitMessage;
import de.bazinga.rotw.network.message.NewBulletMessage;
import de.bazinga.rotw.person.OpponentList;
import de.bazinga.rotw.person.Person;

public class BaseAttackerController extends Controller {
	private static final long serialVersionUID = 1L;
	
	
	private BaseAttacker attacker = null;
	
	private Flag base = null;
	

	private float speed = 1.5f;

	private Ray ray = new Ray(new Vector3f(0,0,0),new Vector3f(0,-1,0));
	private PickResults results = new TrianglePickResults();
	private Vector<Spatial> ground = new Vector<Spatial>();
	

	private Ray fireRay = new Ray(new Vector3f(0,0,0),new Vector3f(0,-1,0));
	private PickResults fireResults = new TrianglePickResults();
	private Vector<Spatial> checkSpatials = new Vector<Spatial>();
	
	private Random r = new Random();
	
	// Shoot-Stuff
	private long lastTimeShoot = 0;
	private long shotLag = 3000;
	private float maxDistance = 30;
	
	public BaseAttackerController(BaseAttacker attacker) {
		this.attacker = attacker;
		
		RotwGameState gameState = (RotwGameState)GameStateManager.getInstance().getChild("gameState");
		DefendYourBase gameMode = (DefendYourBase)gameState.getGameMode();
		
		base = (Flag)gameMode.getBaseStation();
		

		reset();
		resetCollisionVector();
	}
	
	public void update(float tpf) {
		// Reached the Waypoint?
		float delta = 0.3f;
		if(base.getFlagPole().getWorldTranslation().getX() > (attacker.getLocalTranslation().getX() - delta) &&
				base.getFlagPole().getWorldTranslation().getX() < (attacker.getLocalTranslation().getX() + delta) &&
				base.getFlagPole().getWorldTranslation().getZ() > (attacker.getLocalTranslation().getZ() - delta) &&
				base.getFlagPole().getWorldTranslation().getZ() < (attacker.getLocalTranslation().getZ() + delta)) {
			// Attacker reached base
			// Deactivate all
			
			BasicSyncManager syncManager = 
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getSyncManager();
			if(syncManager instanceof Server) {
				BaseAttacker.attackerConquered();
				
				AttackerConqueredMessage attMsg = new AttackerConqueredMessage();
				((Server)syncManager).getServer().sendToAll(attMsg);
			}
		}else{
		
			// Go to Waypoint
			Vector3f movement = new Vector3f(0,0,0);
			
			if((base.getFlagPole().getWorldTranslation().getX() - attacker.getLocalTranslation().getX()) > delta) {
				movement.setX(tpf * speed);
			}else if((base.getFlagPole().getWorldTranslation().getX() - attacker.getLocalTranslation().getX()) < -delta) {
				movement.setX(-tpf * speed);
			}
	
			if((base.getFlagPole().getWorldTranslation().getZ() - attacker.getLocalTranslation().getZ()) > delta) {
				movement.setZ(tpf * speed);
			}else if((base.getFlagPole().getWorldTranslation().getZ() - attacker.getLocalTranslation().getZ()) < -delta) {
				movement.setZ(-tpf * speed);
			}
			
			
			attacker.setLocalTranslation(
					attacker.getLocalTranslation().add(movement));
			
			// Set Zombie on the Ground
			setOnGround();
			
			// Fire at the Players!
			if(((RotwGameState)GameStateManager.getInstance().getChild("gameState")).isServer()) {
				fire();
			}
		}
	}
	public void setOnGround() {		
		// Get New Location
		Vector3f origin = attacker.getLocalTranslation().clone();
		origin.addLocal(new Vector3f(0,2.5f,0));
		
		ray.setOrigin(origin);
		
		results.clear();
		results.setCheckDistance(true);
		
		
		float distance = -5;
		for(int i=0;i<ground.size();i++) {
			ground.get(i).findPick(ray,results);
			
			//check if we hit something
			if(results.getNumber() > 0) {
			   PickData closest = results.getPickData(0);

			   if(distance < 0 || distance > closest.getDistance()) {
				   distance = closest.getDistance();
			   }
			}
		}
		
		if(distance > 0) {
			attacker.getLocalTranslation().setY(
					origin.addLocal(new Vector3f(0,-distance,0)).getY());
		}
	}
	
	public void resetCollisionVector() {
		ground.clear();
		TerrainBlock tb = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainBlock();
		if(tb != null) ground.add(tb);
		
		if(CollidableObjects.getInstance().getObjects("ground") != null) {
			ground.addAll(CollidableObjects.getInstance().getObjects("ground"));
		}
		if(CollidableObjects.getInstance().getObjects("wall") != null) {
			ground.addAll(CollidableObjects.getInstance().getObjects("wall"));
		}
		
		
		
		
		checkSpatials.add(CollidableObjects.getInstance().getObjects("wallNode").get(0));
		checkSpatials.add(CollidableObjects.getInstance().getObjects("groundNode").get(0));
		
		Vector<Spatial> vehicles = CollidableObjects.getInstance().getObjects("vehicle");
		if(vehicles != null) {
			for(Spatial vec:vehicles) {
				checkSpatials.add(vec);
			}
		}
		
		if(AttackerList.getAttackers() != null) {
			for(BaseAttacker att:AttackerList.getAttackers()) {
				checkSpatials.add(att);
			}
		}
	}
	
	
	
	private void fire() {
		if( (System.currentTimeMillis() - lastTimeShoot) > shotLag) {
			if(r.nextInt(3) == 0) {
				// Check for opponent
				Person closestPerson = null;
				float closestDistance = maxDistance+1;
				
				Iterator<Person> it = OpponentList.getInstance().getOpponents().values().iterator();
				while(it.hasNext()) {
					Person p = it.next();
					
					float distance = p.getLocalTranslation().distance(attacker.getLocalTranslation());
					if(distance < maxDistance && distance < closestDistance) {
						closestPerson = p;
					}
					
					if(closestPerson != null) {
						
						// Check if there is a wall between
						Vector3f origin = attacker.getLocalTranslation().clone();
						origin.addLocal(new Vector3f(0,1.5f,0));
						fireRay.setOrigin(origin);
						
						fireRay.setDirection(origin.clone().subtract(closestPerson.getCameraPosition()));
						fireResults.clear();
						
						for(int i=0;i<checkSpatials.size();i++) {
							checkSpatials.get(i).findPick(fireRay,fireResults);
							
							//check if we hit something
							if(fireResults.getNumber() == 0) {
								int damage = 5 + r.nextInt(5);
								closestPerson.hit("Zombie", damage, origin);
								
								RotwGameState gameState = ((RotwGameState)GameStateManager.getInstance().getChild("gameState"));
								
								if(closestPerson != gameState.getPlayer()) {
									// Send HitMessage
									HitMessage hMsg = new HitMessage();
									hMsg.setDamage(damage);
									hMsg.setPlayerLocation(origin);
									hMsg.setWeaponFlag(NewBulletMessage.BASEATTACKER);
									hMsg.setPlayerName(closestPerson.getPlayerName());
									
									((Server)gameState.getSyncManager()).getServer()
										.sendToPlayer(hMsg, closestPerson.getPlayerId());
								}
								
								return ;
							}
						}
						
						
					}
				}
			}
			
			
			lastTimeShoot = System.currentTimeMillis();
		}
	}
	
	public void reset() {
		Vector3f lookDirection = new Vector3f(
				base.getLocalTranslation().getX(), 
				attacker.getLocalTranslation().getY(), 
				base.getLocalTranslation().getZ());
		attacker.lookAt(lookDirection, Vector3f.UNIT_Y);
	}
}
